package com.winit.common.util;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.io.input.BOMInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.io.*;
import java.util.*;

/**
 * Created by wangjian on 16/3/2.
 */
public class FileUtil {

    static final Logger log = LoggerFactory.getLogger(FileUtil.class);

    /**
     * 获取指定目录下文件列表
     *
     * @param file
     * @return
     */
    public static List<String> getFileList(File file, List<String> fileList) {
        File[] files = file.listFiles();
        if (files == null || files.length == 0) {
            return fileList;
        }
        for (int i = 0; i < files.length; i++) {
            if (files[i].isDirectory()) {
                getFileList(files[i], fileList);
            } else {
                fileList.add(files[i].getAbsolutePath());
            }
        }

        return fileList;
    }

    public static List<File> getFileListF(File file, List<File> fileList) {
        File[] files = file.listFiles();
        if (files == null || files.length == 0) {
            return fileList;
        }
        for (int i = 0; i < files.length; i++) {
            if (files[i].isDirectory()) {
                getFileListF(files[i], fileList);
            } else {
                fileList.add(files[i]);
            }
        }

        return fileList;
    }


    /**
     * 比较配置文件内容
     *
     * @param baseFile 基准文件路径
     * @param comFile  需要比较的文件路径
     * @return
     */
    public static Map<String, String> fileCompare(String baseFile, String comFile) {
        return fileCompare(baseFile, comFile,"properties");
    }

    public static Map<String, String> fileCompare(String baseFile, String comFile,String type) {
        Map<String, String> map = new HashMap<String, String>();
        boolean flag = true;
        List<JSONObject> baseList = new ArrayList<>();
        List<JSONObject> comList = new ArrayList<>();
        if("js".equals(type)){
            baseList = getJsKeysFromFile(baseFile);
            comList = getJsKeysFromFile(comFile);
        }else {
            baseList = getPropertieKeysFromFile(baseFile);
            comList = getPropertieKeysFromFile(comFile);
        }
        if (baseList.size() != comList.size()) {
            log.info("比较配置文件内容,配置项个数不同,baseFile=" + baseFile + ",comFile=" + comFile);
            map.put("code", "1");
            map.put("desc", "配置项个数不同");
            return map;
        }
        Integer size = baseList.size();
        if (size > 0) {
            for (int i = 0; i < size; i++) {
                String base = baseList.get(i).getString("key");
                Integer count = 0;
                for (int j = 0; j < size; j++) {
                    String com = comList.get(j).getString("key");
                    if (com.equals(base)) {
                        count = 1;
                        break;
                    }
                }
                if (count == 0) {
                    flag = false;
                    log.info("比较配置文件内容,配置项不存在,key=" + base + ",baseFile=" + baseFile + ",comFile=" + comFile);
                    map.put("desc", "配置项不存在,key=" + base);
                    break;
                }
            }
            if (flag) {
                map.put("code", "0");
            } else {
                map.put("code", "1");
            }
            return map;
        } else {
            map.put("code", "0");
            return map;
        }
    }

    /**
     * 使用diff命令比较文件
     * 忽略空行
     * 忽略等号(=)及(=>)后内容
     *
     * @param baseFile
     * @param comFile
     * @return
     */
    public static Map<String, String> fileCompareByDiff(String configPath, String baseFile, String comFile) {
        log.info("com.winit.common.util.FileUtil.fileCompareByDiff configPath=" + configPath + ",baseFile=" + baseFile
                + ",comFile=" + comFile);
        Map<String, String> map = new HashMap<>();
        StringBuffer filePath = new StringBuffer();
        filePath.append(Constants.SHELL_PATH).append("shell/beetle_compare_file.sh");
        String str = ShellRunUtil.runCmds("bash", filePath.toString(), configPath, baseFile, comFile);
        log.info("com.winit.common.util.FileUtil.fileCompareByDiff rtn=" + str);
        if (str.startsWith("SUCCESS")) {
            map.put("code", "0");
        } else {
            map.put("code", "1");
            if (str.startsWith("ERROR")) {
                map.put("desc", "执行文件比较异常." + str);
            } else {
                log.info("配置文件内容不一致,baseFile=" + baseFile + ",comFile=" + comFile);
                map.put("desc", "配置文件内容不一致,baseFile=" + baseFile + ",comFile=" + comFile + ",str=" + str);
            }
        }
        return map;
    }

    public static List<JSONObject> getPropertieKeysFromFile(String filePath) {
        List<JSONObject> list = new ArrayList<>();
        BufferedReader reader = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return list;
            }
            FileInputStream fileInputStream = new FileInputStream(filePath);
            InputStreamReader inputStreamReader = new InputStreamReader(new BOMInputStream(fileInputStream), "UTF-8");
            reader = new BufferedReader(inputStreamReader);
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                if (tempString.startsWith("#")) {//去除注释
                    continue;
                }
                if (StringUtils.isEmpty(tempString.replace(" ", ""))) {//去除空行
                    continue;
                }
                String[] arms = tempString.split("=");
                JSONObject object = new JSONObject();
                object.put("fileName", file.getName());
                object.put("key", arms[0].trim());
                if (arms.length > 1) {
                    object.put("value", arms[1].trim());
                } else {
                    object.put("value", "");
                }

                list.add(object);
            }
            reader.close();
        } catch (Exception e) {
            log.error("读取文件异常,e:" + e.getMessage());
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (Exception e) {
                    log.error("读取文件异常,e:" + e.getMessage());
                }
            }
        }
        return list;
    }

    public static List<JSONObject> getPhpKeysFromFile(String filePath) {
        List<JSONObject> list = new ArrayList<>();
        BufferedReader reader = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return list;
            }
            FileInputStream fileInputStream = new FileInputStream(filePath);
            InputStreamReader inputStreamReader = new InputStreamReader(new BOMInputStream(fileInputStream), "UTF-8");
            reader = new BufferedReader(inputStreamReader);
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                if (!tempString.contains("=>")) {
                    continue;
                }
                String[] arms = tempString.split("=>");
                JSONObject object = new JSONObject();
                object.put("fileName", file.getName());
                object.put("key", arms[0].trim().replace("'", ""));
                if (arms.length > 1) {
                    String value = arms[1].trim().replace("'", "");
                    if (value.endsWith(",")) {
                        value = value.substring(0, value.length() - 1);
                    }
                    object.put("value", value);
                } else {
                    object.put("value", "");
                }
                list.add(object);
            }
            reader.close();
        } catch (Exception e) {
            log.error("读取文件异常,e:" + e.getMessage());
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (Exception e) {
                    log.error("读取文件异常,e:" + e.getMessage());
                }
            }
        }
        return list;
    }

    public static List<JSONObject> getJsKeysFromFile(String filePath) {
        List<JSONObject> list = new ArrayList<>();
        BufferedReader reader = null;
        try {
            File file = new File(filePath);
            if (!file.exists()) {
                return list;
            }
            FileInputStream fileInputStream = new FileInputStream(filePath);
            InputStreamReader inputStreamReader = new InputStreamReader(new BOMInputStream(fileInputStream), "UTF-8");
            reader = new BufferedReader(inputStreamReader);
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                if (tempString.startsWith("//")) {//去除注释
                    continue;
                }
                if (StringUtils.isEmpty(tempString.trim())) {//去除空行
                    continue;
                }
                String[] arms = tempString.split("=");
                JSONObject object = new JSONObject();
                object.put("fileName", file.getName());
                object.put("key", arms[0].replace("var","").trim());
                if (arms.length > 1) {
                    String value = arms[1].trim().replace("'","");
                    if (value.endsWith(";")) {
                        value = value.substring(0, value.length() - 1);
                    }
                    object.put("value", value);
                } else {
                    object.put("value", "");
                }
                list.add(object);
            }
            reader.close();
        } catch (Exception e) {
            log.error("读取文件异常,e:" + e.getMessage());
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (Exception e) {
                    log.error("读取文件异常,e:" + e.getMessage());
                }
            }
        }
        return list;
    }

    /**
     * 删除文件,包括文件夹
     *
     * @param path
     * @return
     */
    public static boolean deleteFile(String path) {
        if (StringUtils.isEmpty(path)) {
            return false;
        }
        String[] param = new String[3];
        param[0] = "rm";
        param[1] = "-rf";
        param[2] = path;
        String str = ShellRunUtil.runShell(param);
        if (StringUtils.isEmpty(str) || ",".equals(str)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 重命名文件
     *
     * @param oldFilePath
     * @param newFilePath
     * @return
     */
    public static boolean reNameFile(String oldFilePath, String newFilePath) {
        String[] param = new String[3];
        param[0] = "mv";
        param[1] = oldFilePath;
        param[2] = newFilePath;
        String str = ShellRunUtil.runShell(param);
        if (StringUtils.isEmpty(str) || ",".equals(str)) {
            return true;
        } else {
            return false;
        }
    }

    public static void writeLog(String logPath, String log) {
        String[] param = new String[4];
        param[0] = "bash";
        param[1] = Constants.SHELL_PATH + "shell/beetle_write_log.sh";
        param[2] = logPath;
        param[3] = log;
        ShellRunUtil.runShell(param);
    }

    public static void findAllFiles(File dir, List<File> allFiles) {
        File[] fs = dir.listFiles();
        for (int i = 0; i < fs.length; i++) {

            if (fs[i].isDirectory())
                findAllFiles(fs[i], allFiles);
            else
                allFiles.add(fs[i]);
        }
    }

    /**
     * 获取dir下level级目录的所有文件
     *
     * @param dir
     * @param level 1开始
     */
    public static List<File> getFileByLevel(File dir, Integer level) {
        List<File> list = new ArrayList<File>();
        if (level == 1) {
            findFiles(dir, list);
        } else {
            //当前级别目录列表
            List<File> tempList = new ArrayList<File>();
            findFiles(dir, tempList);
            for (int i = 2; i <= level; i++) {
                for (File file : tempList) {
                    if (file.isDirectory()) {
                        findFiles(file, list);
                    }
                }
                if (i < level) {
                    tempList.clear();
                    tempList.addAll(list);
                    list.clear();
                }
            }
        }
        return list;
    }

    private static void findFiles(File dir, List<File> list) {
        File[] fs = dir.listFiles();
        for (File file : fs) {
            if (!".svn".equals(file.getName())) {
                list.add(file);
            }
        }
    }

    /**
     * 获取文件最后一行内容
     *
     * @param filePath
     * @return
     */
    public static String getFileLastLine(String filePath) {
        return getFileByLine(filePath, 1);
    }

    /**
     * 获取文件倒数row行内容
     *
     * @param filePath
     * @param row      row=0时,返回整个文件内容
     * @return
     */
    public static String getFileByLine(String filePath, Integer row) {
        String line = null;
        StringBuilder sb = new StringBuilder();
        File targetFile = new File(filePath);
        Assert.notNull(filePath, "文件路径不能为空");
        Assert.isTrue(targetFile.exists(), "文件不存在,path=" + filePath);
        long fileLength = targetFile.length();
        if (fileLength == 0) {
            log.info("fileLength=" + fileLength);
            return null;
        }

        RandomAccessFile file = null;
        try {
            file = new RandomAccessFile(targetFile, "r");
            Assert.notNull(file);
            Long filePosition = fileLength - 1;


            if (row == 0) {
                filePosition = Long.valueOf(0);
            } else {
                while (filePosition > 0) {
                    filePosition--;
                    file.seek(filePosition);
                    if (file.readByte() == '\n') {
                        row--;
                    }
                    if (row <= 0) {
                        break;
                    }
                }
            }

            if (filePosition == 0) {
                file.seek(0);
            }

            do {
                line = file.readLine();
                if (line == null) break;
                line = new String(line.getBytes("8859_1"), "UTF-8");
                sb.append(line).append("<br>");
            } while (line != null);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                file.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return sb.toString().substring(0, sb.toString().length() - 4);
    }

    /**
     * 获取文件中包含keyWord的最后一行
     *
     * @param filePath
     * @param keyWord
     * @return
     */
    public static String getFileLineByWord(String filePath, String keyWord) {
        BufferedReader reader = null;
        String str = "";
        try {
            FileInputStream fileInputStream = new FileInputStream(filePath);
            InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
            reader = new BufferedReader(inputStreamReader);
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                if (tempString.contains(keyWord)) {
                    str = tempString;
                }
            }
            reader.close();
        } catch (Exception e) {
            log.error("读取文件异常,e:" + e.getMessage());
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (Exception e) {
                    log.error("读取文件异常,e:" + e.getMessage());
                }
            }
        }
        return str;
    }

    public static List<File> sortFileDESC(List<File> list) {
        if (list.size() == 0) {
            return list;
        }
        Collections.sort(list, new Comparator<File>() {
            @Override
            public int compare(File o1, File o2) {
                long a = o1.lastModified();
                long b = o2.lastModified();
                if (a > b) {
                    return -1;
                } else if (a < b) {
                    return 1;
                } else {
                    return 0;
                }
            }
        });
        return list;
    }

    /**
     * 获取配置文件的key value列表
     *
     * @return
     */
    public static List<JSONObject> getConfigKeyAndValue(String filePath) {
        List<JSONObject> list = new ArrayList<>();
        if (filePath.endsWith("properties")) {
            list = getPropertieKeysFromFile(filePath);
        } else if (filePath.endsWith("php")) {
            list = getPhpKeysFromFile(filePath);
        } else if (filePath.endsWith("js")) {
            list = getJsKeysFromFile(filePath);
        }
        return list;
    }


    public static void main(String[] arg) {
        String a = "/Users/wangjian/Desktop/application.properties";
        String type = "properties";
//        String b = "/Users/wangjian/Desktop/config_test.php";
//        System.out.println(FileUtil.fileCompareByDiff("/Users/wangjian/Desktop",a,b));

//        System.out.println(FileUtil.getFileByLine("/Users/wangjian/Desktop/tt",3));

//        for (JSONObject jsonObject : getConfigKeyAndValue(a, type)) {
//            System.out.println(jsonObject);
//        }
    }
}
